﻿//  Copyright (c) 2010 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.Mvc;

namespace DNA.Mvc.jQuery
{
    public class TextBoxBuilder : jQueryComponentBuilder<TextBoxOptions, TextBox, TextBoxBuilder>
    {
        private string[] _source;
        private string _url;
        private InputFilterOptions filterOptions;
        private bool multipleValues = false;

        public TextBoxBuilder(TextBox component, ViewContext context, IViewDataContainer container) : base(component, context, container) { }

        protected override string jQueryPluginName
        {
            get { return "textbox"; }
        }

        private void EnsureOptions() { if (options == null) options = new TextBoxOptions(); }

        public TextBoxBuilder InputFilter(Action<InputFilterOptions> filter)
        {
            if (filterOptions == null)
                filterOptions = new InputFilterOptions();
            filter.Invoke(filterOptions);
            return this;
        }

        public TextBoxBuilder NumericOnly()
        {
            Options(opts => { opts.Clearable = false; });
            return InputFilter(filter =>
            {
                filter.FilterType = FilterTypes.Numbers;
            });
        }

        public TextBoxBuilder NumericOnly(int decimalDigits)
        {
            Options(opts => { opts.Clearable = false; });

            return InputFilter(filter =>
            {
                filter.DecimalDigits = decimalDigits;
                filter.FilterType = FilterTypes.Numbers;
            });
        }

        public TextBoxBuilder LowerCaseOnly()
        {
            return InputFilter(filter =>
            {
                filter.FilterType = FilterTypes.LowercaseLetters;
            });
        }

        public TextBoxBuilder UpperCaseOnly()
        {
            return InputFilter(filter =>
            {
                filter.FilterType = FilterTypes.UppercaseLetters;
            });
        }

        public TextBoxBuilder ValidCharsOnly(string charaters)
        {
            return InputFilter(filter =>
                                 {
                                     filter.FilterType = FilterTypes.Custom;
                                     filter.FilterMode = FilterModes.ValidChars;
                                     filter.ValidChars = charaters;
                                 });
        }

        public TextBoxBuilder InvalidChars(string charaters)
        {
            return InputFilter(filter =>
                               {
                                   filter.FilterType = FilterTypes.Custom;
                                   filter.FilterMode = FilterModes.InvalidChars;
                                   filter.InvalidChars = charaters;
                               });
        }

        public TextBoxBuilder AutoComplete(string[] source)
        {
            return AutoComplete(source, false);
        }

        public TextBoxBuilder AutoComplete(string[] source, bool isMultipleValues)
        {
            if ((source != null) && (source.Length > 0))
            {
                _source = source;
                multipleValues = isMultipleValues;
            }
            return this;
        }

        public TextBoxBuilder AutoComplete(string url)
        {
            return AutoComplete(url, false);
        }

        public TextBoxBuilder AutoComplete(string url, bool isMultipleValues)
        {
            if (!string.IsNullOrEmpty(url))
            {
                _url = url;
                multipleValues = isMultipleValues;
            }
            return this;
        }

        public TextBoxBuilder IconCssClass(string cssClass)
        {
            Options(opts =>
            {
                opts.IconCssClass = cssClass;
            });
            return this;
        }

        public TextBoxBuilder IconImageUrl(string url)
        {
            Options(opts => { opts.IconImageUrl = url; });
            return this;
        }

        public TextBoxBuilder Password() { return this.Password(true); }

        public TextBoxBuilder Password(bool value)
        {
            Component.IsPassword = value;
            return this;
        }

        public override TextBoxBuilder Width(int width)
        {
            Options(opts =>
            {
                opts.Width = width;
            });
            return base.Width(width);
        }

        public TextBoxBuilder Watermark(string watermarktext)
        {
            return Watermark(watermarktext, string.Empty);
        }

        public TextBoxBuilder Watermark(string watermarktext, string cssClass)
        {
            if (!Component.IsPassword)
            {
                Options(opts =>
                {
                    opts.WaterMarkCssClass = cssClass;
                    opts.WaterMarkText = watermarktext;
                });
            }

            return this;
        }
        
        public TextBoxBuilder Value(int value)
        {
            return this.Value(value.ToString());
        }

        public TextBoxBuilder Value(string value)
        {
            EnsureOptions();
            Component.Value = value;
            //options.Value = value;
            return this;
        }

        public override void Render()
        {
            if ((this.options != null) && (this.options.ReadOnly))
                Component.IsReadonly = true;
            base.Render();
            GenerateScripts();
        }

        public override MvcHtmlString GetHtml()
        {
            if ((this.options != null) && (this.options.ReadOnly))
                Component.IsReadonly = true;
            var _html = base.GetHtml();
            GenerateScripts();
            return _html;
        }

        private void GenerateScripts()
        {
            if (!Component.IsPassword)
            {
                #region native autocomplete

                if (_source != null)
                {
                    if (multipleValues)
                    {
                        var autoOptions = new OptionBuilder();

                        string[] formatted = new string[_source.Length];
                        for (int i = 0; i < _source.Length; i++)
                            formatted[i] = "\"" + _source[i] + "\"";
                        string availableTags = "[" + string.Join(",", formatted) + "]";
                        autoOptions.AddFunctionOption("source", new string[] { "request", "response" }, scripts =>
                        {
                            scripts.AppendLine("response($.ui.autocomplete.filter(")
                                     .Append(availableTags)
                                     .Append(",request.term.split( /,\\s*/ ).pop()));");
                        })
                        .AddFunctionOption("focus", scripts =>
                        {
                            scripts.AppendLine("return false");
                        })
                        .AddFunctionOption("select", new string[] { "event", "ui" }, scripts =>
                        {
                            scripts.AppendLine("var terms =this.value.split( /,\\s*/ );")
                                .AppendLine("terms.pop();")
                                .AppendLine("terms.push( ui.item.value );")
                                .AppendLine("terms.push(\"\" );")
                                .AppendLine("this.value = terms.join(\",\" );")
                                .AppendLine("return false;");
                        })
                        .AddOption("minLength", 0);
                        Helper.RegisterStartupScript(jQuerySelector + ".autocomplete(" + autoOptions.ToString() + ")");

                    }
                    else
                    {
                        Helper.jQuery(Component.Id, "autocomplete", new { source = _source });
                    }
                }
                #endregion

                #region remote autocomplete
                if (!string.IsNullOrEmpty(_url) && (_source == null))
                {
                    if (multipleValues)
                    {
                        var autoOptions = new OptionBuilder();
                        autoOptions.AddFunctionOption("source", new string[] { "request", "response" }, scripts =>
                        {
                            scripts.Append("$.getJSON(\"")
                                     .Append(_url)
                                     .Append("\",{ term:")
                                     .Append(" request.term.split( /,\\s*/ ).pop() },response);");
                        })
                        .AddFunctionOption("search", scripts =>
                        {
                            scripts.AppendLine("var term =this.value.split( /,\\s*/ ).pop();")
                                .AppendLine("if ( term.length < 2 ) {return false;}");
                        })
                            .AddFunctionOption("focus", scripts =>
                            {
                                scripts.AppendLine("return false");
                            })
                            .AddFunctionOption("select", new string[] { "event", "ui" }, scripts =>
                            {
                                scripts.AppendLine("var terms =this.value.split( /,\\s*/ );")
                                    .AppendLine("terms.pop();")
                                    .AppendLine("terms.push( ui.item.value );")
                                    .AppendLine("terms.push(\"\" );")
                                    .AppendLine("this.value = terms.join(\",\" );")
                                    .AppendLine("return false;");
                            })
                            .AddOption("minLength", 0);
                        Helper.RegisterStartupScript(jQuerySelector + ".autocomplete(" + autoOptions.ToString() + ")");
                    }
                    else
                        Helper.jQuery(Component.Id, "autocomplete", new { source = _url, minLength = 2 });
                }
                #endregion
            }

            if (filterOptions != null)
                Helper.InputFilter(Component.Id, filterOptions);
        }
    }
}
